/**
 * Copyright (C) 2010 DustedPixels.com
 */
package com.dustedpixels.cirt.model.machine.spectrum.ula;

import com.dustedpixels.cirt.model.core.Circuit;
import com.dustedpixels.cirt.model.core.In;
import com.dustedpixels.cirt.model.core.Out;
import com.dustedpixels.cirt.model.core.Script;
import com.dustedpixels.cirt.model.core.TriState;

/**
 * Ula
 *
 * @author Michal Pociecha-Los (micapolos@gmail.com)
 */
@Circuit
public final class Ula {
  @In public int data;

  @Out @TriState public int address;
  @Out public boolean read;

  @Out public boolean blank;
  @Out public boolean vSync;
  @Out public boolean hSync;
  @Out public int color;
  
  private final HvCounter hvCounter = new HvCounter();
  private final BeamControl beamControl = new BeamControl();
  private final MemoryControl memoryControl = new MemoryControl();
  private final AddressDecoder addressDecoder = new AddressDecoder();
  private final AttrDecoder attrDecoder = new AttrDecoder();
  private final FlashReverseControl flashReverseControl = new FlashReverseControl();
  private final ColorDecoder colorDecoder = new ColorDecoder();
  private final FakeBorderColorControl fakeBorderColorControl = new FakeBorderColorControl();
  
  @Script
  public void update() {
    // Update memory control
    memoryControl.h = hvCounter.h;
    memoryControl.v = hvCounter.v;
    memoryControl.data = data;
    memoryControl.update();
    
    read = memoryControl.read;
    if (read) {
      // Decode memory address
      addressDecoder.addressIn = memoryControl.address;
      addressDecoder.attr = memoryControl.isAttr;
      addressDecoder.decode();
      address = addressDecoder.addressOut;
    }
    
    // Update beam
    beamControl.h = hvCounter.h;
    beamControl.v = hvCounter.v;
    beamControl.update();
    blank = beamControl.blank;
    hSync = beamControl.hSync;
    vSync = beamControl.vSync;
    
    // Update color
    if (!hSync && !vSync) {
      // Decode attribute
      attrDecoder.attr = memoryControl.attr;
      attrDecoder.decode();
      
      // Decode color
      if (memoryControl.screen) {
        // Update flash reverse control
        flashReverseControl.h = hvCounter.h;
        flashReverseControl.update();
        
        colorDecoder.ink = memoryControl.ink;
        colorDecoder.bright = attrDecoder.bright;
        colorDecoder.flash = attrDecoder.flash;
        colorDecoder.flashReverse = flashReverseControl.flashReverse;
        colorDecoder.inkColor = attrDecoder.inkColor;
        colorDecoder.paperColor = attrDecoder.paperColor;
        colorDecoder.decode();
        
        color = colorDecoder.color;
      } else {
        color = fakeBorderColorControl.color;
      }
    }

    // Update fake border color;
    fakeBorderColorControl.update();

    // Finally, increment H/V counters
    hvCounter.update();
  }
}
